package nacos

import (
	"fmt"
	"log"

	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
)

type NacosService interface {
	RegisterServiceInstance() (success bool, err error)
	DeregisterServiceInstance() (success bool, err error)
	GetServiceInfo(serviceName string) (string, uint64, error)
	GetConfig() (string, error)
	ListenConfig() error
	CancelListenConfig() error
}

func NewNacosService() NacosService {
	configClient := createConfigClient()
	namingClient := createNamingClient()

	return nacosService{
		ConfigClient:  configClient,
		NamingClient:  namingClient,
		ServerConfigs: serverConfigs,
	}
}

type nacosService struct {
	ConfigClient  config_client.IConfigClient
	NamingClient  naming_client.INamingClient
	ServerConfigs []constant.ServerConfig
}

var serverConfigs []constant.ServerConfig = []constant.ServerConfig{
	{
		IpAddr: "127.0.0.1", // Nacos server IP (replace with actual server address)
		Port:   8848,        // Default Nacos port
	},
}

func (nacosService nacosService) RegisterServiceInstance() (success bool, err error) {
	return nacosService.NamingClient.RegisterInstance(vo.RegisterInstanceParam{
		Ip:          "127.0.0.1", // Current service IP address.
		Port:        8088,        // Current service port.
		ServiceName: "payment-service",
		Weight:      1,
		Enable:      true,
		Healthy:     true,
		Ephemeral:   true,
		Metadata:    map[string]string{"idc": "shanghai"},
	})
}

func (nacosService nacosService) DeregisterServiceInstance() (success bool, err error) {
	return nacosService.NamingClient.DeregisterInstance(vo.DeregisterInstanceParam{
		Ip:          "127.0.0.1", // Current service IP address.
		Port:        8088,        // Current service port.
		ServiceName: "payment-service",
		Ephemeral:   true,
	})
}

func (nacosService nacosService) GetServiceInfo(serviceName string) (ipAddress string, port uint64, err error) {
	// SelectOneHealthyInstance return one instance by WRR strategy for load balance
	// And the instance should be health=true,enable=true and weight>0
	instance, err := nacosService.NamingClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
		ServiceName: serviceName,
	})

	return instance.Ip, instance.Port, err
}

func (nacosService nacosService) GetConfig() (content string, err error) {
	return nacosService.ConfigClient.GetConfig(vo.ConfigParam{
		DataId: "payment-service.yml",
	})
}

func (nacosService nacosService) ListenConfig() error {
	return nacosService.ConfigClient.ListenConfig(vo.ConfigParam{
		DataId: "payment-service.yml",
		Group:  "DEFAULT_GROUP",
		OnChange: func(namespace, group, dataId, data string) {
			fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
		},
	})
}

func (nacosService nacosService) CancelListenConfig() error {
	return nacosService.ConfigClient.CancelListenConfig(vo.ConfigParam{
		DataId: "payment-service.yml",
		Group:  "DEFAULT_GROUP",
	})
}

func createConfigClient() config_client.IConfigClient {
	configClient, err := clients.NewConfigClient(
		vo.NacosClientParam{
			// ClientConfig:  &clientConfig,
			ServerConfigs: serverConfigs,
		},
	)

	if err != nil {
		log.Fatalf("Failed to create Nacos config client: %v", err)
	}

	return configClient
}

func createNamingClient() naming_client.INamingClient {
	namingClient, err := clients.NewNamingClient(
		vo.NacosClientParam{
			// ClientConfig:  &clientConfig,
			ServerConfigs: serverConfigs,
		},
	)

	if err != nil {
		log.Fatalf("Failed to create Nacos naming client: %v", err)
	}

	return namingClient
}
